/*matchSide.h*/

#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#include <cvaux.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

// normalizeIMG - normalize an Image's first entry to between 0 and 255
// assumes that the image is grayscale
// src, IplImage *, source image
// dst, IplImage *, destination image
// debug, int, prints debug information if set
// return, int, 0 if fails, 1 if succeeds
int normalizeIMG(IplImage *src, IplImage *dst, bool debug=0){
    if(src->height != dst->height){return 0;}
    if(src->width != dst->width){return 0;}
    CvScalar cs = cvScalar(0, 0, 0, 0);
    CvScalar csMin = cvScalar(255, 0, 0, 0);
    CvScalar csMax = cvScalar(0, 0, 0, 0);
    int i, j;
    if(debug){
        printf("Start, normalizeIMG:\n");
        cvNamedWindow("Normal Source", 0);
        cvShowImage("Normal Source", src);
        cvWaitKey(0);
    }
    for(i=0;i<src->height;i++){
        for(j=0;j<src->width;j++){
            cs = cvGet2D(src, i, j);
            if(cs.val[0] < csMin.val[0]){
                csMin.val[0] = cs.val[0];
            }
            if(cs.val[0] > csMax.val[0]){
                csMax.val[0] = cs.val[0];
            }
        }
    }
    if(debug){
        printf("Min: %f, Max %f\n", csMin.val[0], csMax.val[0]);
    }
    for(i=0;i<src->height;i++){
        for(j=0;j<src->width;j++){
            cs = cvGet2D(src, i, j);
            cs.val[0] = (cs.val[0] - csMin.val[0]) * 255 / csMax.val[0];
            cvSet2D(dst, i, j, cs);
        }
    }
    if(debug){
        cvNamedWindow("Normal Destination", 1);
        cvShowImage("Normal Destination", dst);
        cvWaitKey(0);
        cvDestroyWindow("Normal Source");
        cvDestroyWindow("Normal Destination");
        printf("End, normalizeIMG:\n");
    }
    return 1;
}

// smoothDiff - smooths an image then places the difference
// between the source and the smoothed image
// src, IplImage *, source image
// dst, IplImage *, destination image
// debug, int, prints debug information if set
// return, int, 0 if fails, 1 if succeeds
int smoothDiff(IplImage *src, IplImage *dst, int size = 3, int debug=0){
    if(src->height != dst->height){return 0;}
    if(src->width != dst->width){return 0;}
    if(!(size % 2)){return 0;}
    IplImage *smooth = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
    int i, j;
    double m=0.0;
    if(debug){
        printf("Start, smoothDiff:\n");
        cvNamedWindow("Original Image", 0);
        cvShowImage("Original Image", src);
        cvWaitKey(0);
    }
    cvSmooth(src, smooth, CV_GAUSSIAN, size, 0, 0, 0);
    if(debug){
        cvNamedWindow("Smoothed Image", 1);
        cvShowImage("Smoothed Image", smooth);
        cvWaitKey(0);
    }
    for(i=0;i<src->height;i++){
        for(j=0;j<src->width;j++){
            double original = cvGet2D(src,i,j).val[0];
            double smoothed = cvGet2D(smooth,i,j).val[0];
            m = original + (original - smoothed);
            if(m < 0.0)
                m = 0.0;
            if(m > 255.0)
                m = 255.0;
            cvSet2D(dst, i, j, cvScalar(m, 0, 0, 0));
        }
    }
    if(debug){
        cvNamedWindow("Smoothed Difference", 2);
        cvShowImage("Smoothed Difference", smooth);
        cvWaitKey(0);
        cvDestroyWindow("Original Image");
        cvDestroyWindow("Smoothed Image");
        cvDestroyWindow("Smoothed Difference");
        printf("End, smoothDiff:\n");
    }
    return 1;
}

void highpass(IplImage *src, IplImage *dst, int size=3, int debug=0){
   if(src->width != dst->width){return;}
   if(src->height != dst->height){return;}
   IplImage *smooth = cvCreateImage(cvSize(src->width, src->height), 8, 1);
   cvSmooth(src, smooth, CV_GAUSSIAN, size, 0, 0, 0);
   for(int i=0;i<src->height;i++){
      for(int j=0;j<src->width;j++){
         CvScalar c1 = cvGet2D(smooth,i,j);
         CvScalar c2 = cvGet2D(src,i,j);
         CvScalar c3 = cvScalar(0,0,0,0);
         c3.val[0] = c2.val[0] + c2.val[0] - c1.val[0];
         if(c3.val[0] < 0) c3.val[0] = 0;
         else if(c3.val[0] > 255){c3.val[0] = 255;}
         cvSet2D(dst,i,j,c3);
      }
   }
}

void lowpass(IplImage *src, IplImage *dst, int size=3, int debug=0){
   cvSmooth(src, dst, CV_GAUSSIAN, size, 0, 0, 0);
}

IplImage *haarwavelet(IplImage *src, int size=3, int debug=0){
   if(src->width%2 != 0 || src->height%2 != 0){return src;}
   else{
      IplImage *tmp1 = cvCreateImage(cvSize(src->width,src->height),8,1);
      lowpass(src,tmp1,size,debug);
      IplImage *tmp2 = cvCreateImage(cvSize(src->width,src->height),8,1);
      highpass(src,tmp2,size,debug);
      IplImage *tmp3 = cvCreateImage(cvSize(src->width/2,src->height/2),8,1);
      IplImage *tmp4 = cvCreateImage(cvSize(src->width/2,src->height/2),8,1);
      cvResize(tmp1,tmp3);
      cvResize(tmp2,tmp4);
      if(tmp3->width%2 != 0 || tmp3->height%2 != 0){
         return tmp4;
      }else{
         return haarwavelet(tmp3,size,debug);
      }
   }
}
